#ifndef __FRAME_BUILDER_H__
#define __FRAME_BUILDER_H__ 1

#include "bit_source.h"
#include "ext_bit_source.h"
#include "properties_reader.h"

#include <vector>

/**
 * @brief Assembles bits to a frame. Splits a frame to bits.
 *
 * this needs a IStegIO as "real" data source/sink where
 * the bytes are read from and written to
 */
class CFrameBuilder : public IBitSource
{
public:

	/**
	 * @param pStegIO data source/sink for stego payload
	 */
	CFrameBuilder(CPropertiesReader* pConfig,
			IExtBitSource* pExtBitSource);

	virtual ~CFrameBuilder();
	virtual int getBit(bool& pReadBit);
	virtual bool putBit(bool pWriteBit);

private:
	enum EFrameState
	{
		STATE_NO_FRAME = 0,
		STATE_PREAMBLE,
		STATE_PAYLOAD,
	};
	class CBitRingBuffer
	{
	public:
		CBitRingBuffer(std::vector<bool> *pPreamble,
				unsigned int pBitStuffIndex);

		/**
		 * @param pForce If true then no bit stuffing is done
		 *        -> new preamble is possible
		 * @param pAllowBitStuffing True allow bit stuffing.
		 *        False -> no bit stuffing -> could create a new preamble
		 * @param pNewPreamble (OUT) Get info if a new preamble is created.
		 *        A new preamble should only be possible by pAllowBitStuffing is
		 *        false.
		 * @return false for no add instead it made a bit stuffing
		 *         false -> bit stuffing
		 */
		bool put(bool pValue, bool pAllowBitStuffing);
		bool put(bool pValue, bool pAllowBitStuffing, bool &pNewPreamble);

		/* for getBit necessary */
		bool prevBitWasStuff();
		bool getPrevOriginalValue();
		void resetPrevBitStuff();

		/* for gutBit necessary */
		bool hasOverflow();
		bool getOverflowValue();
		bool isOverflowBitStuff();

		/**
		 * get count of used elements
		 */
		unsigned int count();
		void clear();

		/**
		 * @note doesn't remove the element from the ring buffer
		 *
		 * @param pOffset Can be a value from 0 to count()-1.
		 *        A value of 0 will return the longest stored value and count()-1
		 *        the newest one.
		 * @return true for successful access or false for out of range.
		 */
		bool get(unsigned int pOffset, bool &pValue);

		/**
		 * Check if the current ring buffer needs bit stuffing.
		 */
		bool isBitStuffingNeeded();

		bool getBitStuffValue();

		/**
		 * @return True if the preamble is saved into the ring buffer
		 */
		bool isPreamble();
	private:
		unsigned int mPutIndex; // next free place
		unsigned int mGetIndex;
		bool mFull;
		unsigned int mBitStuffIndex;
		bool mBitStuffValue;
		const std::vector<bool> *mPreamble;
		std::vector<bool> mBuffer;
		/**
		 * This buffer (mBitStuffBuf) says if the bit from mBuffer is a
		 * normal ( = false) or a stuffing bit ( = true)
		 */
		std::vector<bool> mBitStuffBuf;

		bool mPrevBitWasStuff;
		bool mPrevOriginalValue;

		bool mHasOverflow;
		bool mOverflowValue;
		bool mOverflowIsBitStuff;
	};

	static const std::string sIniSection;

	bool mError;
	CPropertiesReader* mConfig;
	IExtBitSource* mExtBitSource;
	std::vector<bool> mPreamble;

	EFrameState mReadState;
	unsigned int mReadBitIndex; // used for peramble
	CBitRingBuffer *mReadRingBuf;
	unsigned int mReadBitCount;

	EFrameState mWriteState;
	unsigned int mWriteBitIndex; // used for peramble
	CBitRingBuffer *mWriteRingBuf;
	bool mWriteFirst;
	unsigned int mWriteBitCount; // to check max frame length

	//unsigned char *mWriteBuf; // is used for putBit payload

	CFrameBuilder(const CFrameBuilder& );
	CFrameBuilder& operator=(const CFrameBuilder& );
	//bool createFrame()

	void testRingBuf(CBitRingBuffer *pRingBuf);
};

#endif // __FRAME_BUILDER_H__
